package com.mcp.server;


import com.mcp.server.handler.ToolHandler;
import com.mcp.server.model.McpError;
import com.mcp.server.model.McpRequest;
import com.mcp.server.model.McpResponse;
import com.mcp.util.JsonUtils;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * MCP服务端核心类
 * 支持Stdio通信方式
 */
public class McpServer {
    private final ToolHandler toolHandler = new ToolHandler();
    private static final int SOCKET_PORT = 8080; // Socket监听端口
    private static final int HTTP_PORT = 8081;   // HTTP监听端口


    // SSE客户端连接管理
    private final ConcurrentMap<String, PrintWriter> sseClients = new ConcurrentHashMap<>();

    public void start() {
        System.out.println("MCP Server启动 (PID: " + ProcessHandle.current().pid() + ")");

        // 启动Stdio处理线程
        new Thread(this::startStdioServer).start();
    }

    private void startStdioServer() {

        try (BufferedReader in = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(System.out)) {

            String line;
            while ((line = in.readLine()) != null) {
                System.out.println("发送数据" + line);
                try {
                    // 1. 解析请求
                    McpRequest request = JsonUtils.fromJson(line, McpRequest.class);

                    // 2. 处理请求
                    McpResponse response = processRequest(request);

                    // 3. 返回响应
                    out.println(JsonUtils.toJson(response));
                    out.flush();

                } catch (Exception e) {
                    // 处理解析错误
                    McpResponse errorResponse = McpResponse.error(null,
                            new McpError(McpError.PARSE_ERROR, "请求解析失败: " + e.getMessage(), null));
                    out.println(JsonUtils.toJson(errorResponse));
                    out.flush();
                }
            }
        } catch (IOException e) {
            System.err.println("服务器异常: " + e.getMessage());
        }
    }

    // Socket服务器实现
    private void startSocketServer() {
        try (ServerSocket serverSocket = new ServerSocket(SOCKET_PORT)) {
            System.out.println("Socket服务器启动，监听端口: " + SOCKET_PORT);

            while (true) {
                try (Socket socket = serverSocket.accept();
                     BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                     PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {

                    String line;
                    while ((line = in.readLine()) != null) {
                        try {
                            McpRequest request = JsonUtils.fromJson(line, McpRequest.class);
                            McpResponse response = processRequest(request);
                            out.println(JsonUtils.toJson(response));
                        } catch (Exception e) {
                            McpResponse errorResponse = McpResponse.error(null,
                                    new McpError(McpError.PARSE_ERROR, "请求解析失败: " + e.getMessage(), null));
                            out.println(JsonUtils.toJson(errorResponse));
                        }
                    }
                } catch (IOException e) {
                    System.err.println("Socket服务器异常: " + e.getMessage());
                }
            }
        } catch (IOException e) {
            System.err.println("无法启动Socket服务器: " + e.getMessage());
        }
    }

    // HTTP+SSE服务器实现
    private void startHttpServer() {
        try {
            HttpServer server = HttpServer.create(new InetSocketAddress(HTTP_PORT), 0);

            // SSE连接端点
            server.createContext("/events", new SseHandler());

            // API端点
            server.createContext("/api/mcp", new ApiHandler());

            server.setExecutor(null); // 使用默认执行器
            server.start();
            System.out.println("HTTP服务器启动，监听端口: " + HTTP_PORT);
        } catch (IOException e) {
            System.err.println("无法启动HTTP服务器: " + e.getMessage());
        }
    }

    // SSE处理器
    private class SseHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            if ("GET".equals(exchange.getRequestMethod())) {
                String clientId = exchange.getRemoteAddress().toString();

                // 设置SSE响应头
                exchange.getResponseHeaders().add("Content-Type", "text/event-stream");
                exchange.getResponseHeaders().add("Cache-Control", "no-cache");
                exchange.getResponseHeaders().add("Connection", "keep-alive");
                exchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");

                // 发送响应状态
                exchange.sendResponseHeaders(200, 0);

                // 获取输出流
                OutputStream out = exchange.getResponseBody();
                PrintWriter writer = new PrintWriter(out);

                // 保存客户端连接
                sseClients.put(clientId, writer);

                // 发送初始连接消息
                writer.println("event: connected");
                writer.println("data: " + JsonUtils.toJson(McpResponse.success(null, "SSE连接已建立")));
                writer.println();
                writer.flush();

                // 保持连接直到客户端断开
                try {
                    while (true) {
                        Thread.sleep(30000); // 每30秒发送一次心跳
                        writer.println("event: heartbeat");
                        writer.println("data: " + System.currentTimeMillis());
                        writer.println();
                        writer.flush();
                    }
                } catch (InterruptedException e) {
                    // 客户端断开连接
                } finally {
                    // 移除客户端连接
                    sseClients.remove(clientId);
                    out.close();
                }
            } else {
                exchange.sendResponseHeaders(405, -1); // 方法不允许
            }
        }
    }

    // API处理器
    private class ApiHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            if ("POST".equals(exchange.getRequestMethod())) {
                try {
                    // 读取请求体
                    BufferedReader reader = new BufferedReader(
                            new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8));
                    StringBuilder requestBody = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        requestBody.append(line);
                    }

                    // 解析请求
                    McpRequest request = JsonUtils.fromJson(requestBody.toString(), McpRequest.class);

                    // 处理请求
                    McpResponse response = processRequest(request);

                    // 发送响应
                    String responseJson = JsonUtils.toJson(response);
                    byte[] responseBytes = responseJson.getBytes(StandardCharsets.UTF_8);

                    exchange.getResponseHeaders().add("Content-Type", "application/json; charset=utf-8");
                    exchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
                    exchange.sendResponseHeaders(200, responseBytes.length);

                    OutputStream out = exchange.getResponseBody();
                    out.write(responseBytes);
                    out.close();

                    // 如果需要，通过SSE发送额外通知
                    if (response.getResult() != null && !sseClients.isEmpty()) {
                        String sseData = JsonUtils.toJson(response);
                        for (PrintWriter clientWriter : sseClients.values()) {
                            clientWriter.println("event: response");
                            clientWriter.println("data: " + sseData);
                            clientWriter.println();
                            clientWriter.flush();
                        }
                    }

                } catch (Exception e) {
                    McpResponse errorResponse = McpResponse.error(null,
                            new McpError(McpError.PARSE_ERROR, "请求解析失败: " + e.getMessage(), null));
                    String errorJson = JsonUtils.toJson(errorResponse);
                    byte[] errorBytes = errorJson.getBytes(StandardCharsets.UTF_8);

                    exchange.getResponseHeaders().add("Content-Type", "application/json; charset=utf-8");
                    exchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
                    exchange.sendResponseHeaders(400, errorBytes.length);

                    OutputStream out = exchange.getResponseBody();
                    out.write(errorBytes);
                    out.close();
                }
            } else {
                exchange.sendResponseHeaders(405, -1); // 方法不允许
            }
        }
    }

    private McpResponse processRequest(McpRequest request) {
        // 验证请求
        if (!request.isValid()) {
            return McpResponse.error(request.getId(),
                    new McpError(McpError.INVALID_REQUEST, "无效请求", null));
        }

        try {
            // 路由到工具处理器
            Object result = toolHandler.handle(request.getMethod(), request.getParams());
            return McpResponse.success(request.getId(), result);

        } catch (NoSuchMethodException e) {
            return McpResponse.error(request.getId(),
                    new McpError(McpError.METHOD_NOT_FOUND, "方法不存在", null));
        } catch (Exception e) {
            return McpResponse.error(request.getId(),
                    new McpError(McpError.INTERNAL_ERROR, "处理失败: " + e.getMessage(), null));
        }
    }

    public static void main(String[] args) {
        new McpServer().start();
    }
}